#include "WifiSmartconfig.h"

// wifi进程
pt autoPrecess;
pt smartPrecess;
pt socketPrecess;

const int WIFI_CONFIG_PIN = 48; // 进入配网按钮
const int CLEAR_WIFI_PIN = 47;  // 清空wifi按钮

uint8_t wifiState = 0;     // wifi状态：5-已清空wifi账号密码；0-未配网；1-wifi自动连接中；2-蓝牙配网中；3-wifi配网成功，自动进入连接TCP；4-TCP连接成功
uint16_t auto_i = 0;       // 自动联网计时器
uint16_t auto_time = 20;   // 自动联网时长 20*1 = 20秒
uint16_t smart_i = 0;      // 蓝牙配网状态计时器
uint16_t smart_time = 120; // 蓝牙配网时长 120*0.5 = 60秒
uint16_t tcp_i = 0;        // SOCKET连接计时器
uint16_t tcp_time = 60;    // SOCKET连接时长 120*0.5 = 60秒

String mac_address = ""; //

#define TCOM_STX 0x55
#define TCOM_ETX 0xFA
#define TCOM_MSG_CMD 0x00
#define TCOM_MSG_ACK 0x01

#define TCOM_CMD_VER 0x00
#define TCOM_CMD_SN 0x01
#define TCOM_CMD_STATE 0x02
#define TCOM_CMD_HEART 0x03

#define TCOM_CMD_START 0x13
#define TCOM_CMD_STOP 0x14
#define TCOM_CMD_RESULT 0x15
#define TCOM_CMD_SETA 0x18
#define TCOM_CMD_SETB 0x19
#define DEV_HWVER 0x01
#define DEV_SWVER 0x01
#define DEVICE_NAME "HKKJ"
uint8_t DEVICE_SN[6] = {'8', '8', '8', '8', '8', '8'};
uint8_t HeartBeatVal = 0;
uint8_t SequenceId = 0;

// socket连接
const char *host = "192.168.124.1"; // This should not be changed
// const char *host = "118.178.238.205"; // This should not be changed
const int httpPort = 5025; // This should not be changed
WiFiClient client;

void network_init()
{
  pinMode(CLEAR_WIFI_PIN, INPUT_PULLUP);
  pinMode(WIFI_CONFIG_PIN, INPUT_PULLUP);
  client.stop(); // 断开所有socket连接
  delay(1000);
  get_mac_address();
  PT_INIT(&autoPrecess);   // 自动联网进程
  PT_INIT(&smartPrecess);  // smart配网进程
  PT_INIT(&socketPrecess); // websocket连接进程
}

void network_precess()
{
  PT_SCHEDULE(SmartConfig(&smartPrecess));

  if (wifiState != 5)
  {
    // Serial.println("开始自动配网和socket连接");
    PT_SCHEDULE(AutoConfig(&autoPrecess));
    PT_SCHEDULE(socketLink(&socketPrecess));
  }

  reset_wifi();
  readResponse();
  // Serial.println("循环。。。");
}

void reset_wifi(void)
{
  if (digitalRead(CLEAR_WIFI_PIN) == LOW)
  {
    delay(100); // 消抖
    if (digitalRead(CLEAR_WIFI_PIN) == LOW)
    {
      Serial.println("Resetting WiFi configuration...");
      WiFi.eraseAP();
      delay(10);     // 等待重置完成
      ESP.restart(); // 重启ESP32以应用更改
    }
  }
}

int SmartConfig(struct pt *pt)
{
  PT_BEGIN(pt);
  if (digitalRead(WIFI_CONFIG_PIN) == LOW)
  {
    PT_SLEEP(pt, 100); // 消抖
    if (digitalRead(WIFI_CONFIG_PIN) == LOW)
    {
      wifiState = 2;
      WiFi.mode(WIFI_STA);
      Serial.println("\r\nWait for Smartconfig...");
      WiFi.beginSmartConfig();
    }
  }
  if (wifiState == 2)
  {
    if (smart_i >= smart_time)
    {
      // 配网超时，退出配网状态，并恢复计数器
      Serial.print("蓝牙配网超时,smart_i：");
      wifiState = 0;
      smart_i = 0;
    }
    else
    {
      Serial.print("配网中,smart_i：");
      Serial.println(smart_i);
      PT_SLEEP(pt, 500); // wait for a second
      if (WiFi.smartConfigDone())
      {
        Serial.println("SmartConfig Success");
        Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
        Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
        wifiState = 3;
        smart_i = 0;
      }
      else
      {
        smart_i++;
      }
    }
  }
  PT_END(pt);
}
int AutoConfig(struct pt *pt)
{
  PT_BEGIN(pt);

  if (wifiState == 0)
  {
    // 未配网
    Serial.println("auto config begin");
    // 首次进入自动联网，不用重复begin
    wifiState = 1;
    WiFi.begin();
    if (WiFi.psk().length() == 0)
    {
      Serial.println("无wifi账号密码");
      wifiState = 5;
      return 1;
    }
  }
  else if (wifiState == 1)
  {
    Serial.println("wifi自动连接中");
    if (auto_i >= auto_time)
    {
      // 20秒 自动联网超时，重连wifi
      wifiState = 0;
      auto_i = 0;
    }
    else
    {
      Serial.print("自动中,auto_i:");
      Serial.println(auto_i);
      PT_SLEEP(pt, 1000); // wait for a second
      int wstatus = WiFi.status();
      if (wstatus == WL_CONNECTED)
      {
        Serial.println("WIFI AutoConfig Success");
        Serial.printf("SSID:%s", WiFi.SSID().c_str());
        Serial.printf(", PSW:%s\r\n", WiFi.psk().c_str());
        Serial.print("LocalIP:");
        Serial.print(WiFi.localIP());
        Serial.print(" ,GateIP:");
        Serial.println(WiFi.gatewayIP());
        wifiState = 3;
        auto_i = 0;
      }
      else
      {
        Serial.print("WIFI AutoConfig Waiting......");
        Serial.println(wstatus);
        auto_i++;
      }
    }
  }

  PT_END(pt);
}

int socketLink(struct pt *pt)
{
  PT_BEGIN(pt);
  if (wifiState == 3)
  {
    if (tcp_i >= tcp_time)
    {
      // 60秒 TCP连接超时，先判断wifi是否断开，重连TCP
      if (WiFi.status() == WL_CONNECTED)
      {
        // wifi连着中，重连SOCKET就好了
        /* code */
        // wifiState = 3;
        // 触发重启
        ESP.restart();
      }
      else
      {
        // wifi已断开，进入重连wifi状态
        wifiState = 0;
      }
      tcp_i = 0;
    }
    else
    {
      if (client.connected())
      {
        Serial.println("SOCKET LINK Success");
        // client.print("SOCKET LINK Success");
        wifiState = 4;
        tcp_i = 0;
      }
      else
      {
        // 配网成功，进入SOCKET自动连接状态
        if (!client.connect(host, httpPort))
        {
          Serial.print("SOCKET LINK Waiting............tcp_i:");
          Serial.println(tcp_i);
          client.stop();
          PT_SLEEP(pt, 7000); // 7秒再重连一次tcp
          tcp_i += 10;
        }
      }
    }
  }
  else if (wifiState == 4)
  {
    // tcp连接成功后，持续保持检测tcp状态
    if (!client.connected())
    {
      // 检测到tcp断开了，再检测wifi状态
      if (WiFi.status() == WL_CONNECTED)
      {
        // wifi连着中，重连SOCKET就好了
        /* code */
        wifiState = 3;
      }
      else
      {
        // wifi已断开，进入重连wifi状态
        wifiState = 0;
      }
    }
    else
    {
      sendHeartbeat();
    }

    PT_SLEEP(pt, 5000); // wait for a second
    Serial.println("tcp连接成功后，每隔5秒检测一次tcp和wifi是否有断开");
  }

  PT_END(pt);
}

void get_mac_address(void)
{
  // 获取WiFi接口的MAC地址
  WiFi.macAddress(DEVICE_SN);
  for (int i = 0; i < 6; i++)
  {
    // 创建一个临时的String对象
    String temp = String(DEVICE_SN[i], HEX);
    // 转换为大写
    temp.toUpperCase();
    // 添加到mac_address中
    mac_address += temp;
  }
  // 打印MAC地址
  Serial.print("MAC: ");
  Serial.println(mac_address);
}

void sendData(uint8_t *data, uint16_t length)
{
  if (wifiState != 4)
  {
    return;
  }
  Serial.print("发送数据：");
  for (int i = 0; i < length; i++)
  {
    if (data[i] < 0x10)
    {
      Serial.print("0"); // 如果值小于16，则打印前导零
    }
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
  client.write(data, length);
}

void readResponse()
{
  if (wifiState != 4)
  {
    return;
  }
  unsigned long timeout = millis();
  if (client.available())
  {

    uint8_t pBuf[256];
    uint8_t sBuf[256];
    uint16_t len = 0;
    unsigned short crc, crc_t;
    uint8_t spstate = 0;
    memset(pBuf, 0, sizeof(pBuf));
    // String line = client.readStringUntil('\r');
    int bytesRead = client.readBytes((char *)pBuf, sizeof(pBuf));
    // 打印实际读取的字节数
    Serial.print("Bytes read: ");
    Serial.println(bytesRead);
    if (pBuf[1] != TCOM_MSG_CMD)
    {
      Serial.println("非响应代码");
      return;
    }
    Serial.println("是响应代码");

    // 确保有足够的数据来解析长度和CRC
    if (bytesRead < 9)
    { // 至少需要有7个字节（长度字段2个，CRC字段2个，加上一些额外字节）
      Serial.println("数据不足以解析长度和CRC");
      return;
    }

    len = ((pBuf[5] << 8) & 0xFF00) | pBuf[6];
    if (bytesRead < len + 9)
    { // 检查是否有足够的数据来包含整个消息和CRC
      Serial.println("数据不足以包含整个消息和CRC");
      return;
    }

    crc = ((pBuf[len + 7] << 8) & 0xFF00) | pBuf[len + 8];
    crc_t = luckin_calcrc(pBuf, len + 7);
    if (crc_t != crc)
    {
      return;
    }

    // 打印缓冲区内容（以十六进制形式显示每个字节）
    // Serial.print("Buffer content (hex): ");
    // for (int i = 0; i < bytesRead; i++)
    // {
    //   if (pBuf[i] < 0x10)
    //   {
    //     Serial.print("0"); // 如果值小于16，则打印前导零
    //   }
    //   Serial.print(pBuf[i], HEX);
    //   Serial.print(" ");
    // }
    // Serial.println();
    SequenceId = pBuf[4];
    if (pBuf[3] == TCOM_CMD_SN)
    {
      // 发送设备信息
      Serial.print("DEVICE_SN：");
      Serial.println(mac_address);

      sBuf[0] = TCOM_STX;     // 帧头
      sBuf[1] = TCOM_MSG_ACK; // 消息类型
      sBuf[2] = pBuf[2];      // 协议版本
      sBuf[3] = pBuf[3];      // 通信命令
      sBuf[4] = pBuf[4];      // 消息流水号
      sBuf[5] = 0x00;         // 消息体长度
      sBuf[6] = 0x12;         // 消息体长度

      memcpy(sBuf + 7, DEVICE_NAME, 4);
      memcpy(sBuf + 11, mac_address.c_str(), 12);
      sBuf[23] = DEV_HWVER;
      sBuf[24] = DEV_SWVER;
    }
    else if (pBuf[3] == TCOM_CMD_STATE)
    {
      sBuf[0] = TCOM_STX;     // 帧头
      sBuf[1] = TCOM_MSG_ACK; // 消息类型
      sBuf[2] = pBuf[2];      // 协议版本
      sBuf[3] = pBuf[3];      // 通信命令
      sBuf[4] = pBuf[4];      // 消息流水号
      sBuf[5] = 0x00;         // 消息体长度
      sBuf[6] = 0x02;         // 消息体长度
      sBuf[7] = 0;
      sBuf[8] = 0;
    }
    // START DEVICE
    else if (pBuf[3] == TCOM_CMD_START)
    {
      sBuf[0] = TCOM_STX;     // 帧头
      sBuf[1] = TCOM_MSG_ACK; // 消息类型
      sBuf[2] = pBuf[2];      // 协议版本
      sBuf[3] = pBuf[3];      // 通信命令
      sBuf[4] = pBuf[4];      // 消息流水号
      sBuf[5] = 0x00;         // 消息体长度
      sBuf[6] = 0x01;         // 消息体长度
      spstate = 0;            // 0x00:启动成功，0x01:设备已启动，0x02:盖子未改好,0x03:运行速度数据错误,0x04:运行数据段数错误
      // if (digitalRead(CLEAR_WIFI_PIN) == LOW) // 霍尔检测，盖子已盖上
      // {
      //   // spstate = 1;
      // }
      // else
      // {
      //   spstate = 2;
      // }
      sBuf[7] = spstate;
      // 给信号启动或调用启动函数
      //  motorStart();
    }
    else if (pBuf[3] == TCOM_CMD_STOP)
    {
      sBuf[0] = TCOM_STX;     // 帧头
      sBuf[1] = TCOM_MSG_ACK; // 消息类型
      sBuf[2] = pBuf[2];      // 协议版本
      sBuf[3] = pBuf[3];      // 通信命令
      sBuf[4] = pBuf[4];      // 消息流水号
      sBuf[5] = 0x00;         // 消息体长度
      sBuf[6] = 0x01;         // 消息体长度
      sBuf[7] = 00;
      // motorStop(1);  //给信号停止或调用停止函数
    }
    len = ((sBuf[5] << 8) & 0xFF00) | sBuf[6];
    crc = luckin_calcrc(sBuf, len + 7);
    sBuf[len + 7] = (crc >> 8) & 0xFF;
    sBuf[len + 8] = crc & 0xFF;
    sendData(sBuf, len + 9);
  }
}

unsigned short luckin_calcrc(unsigned char *ptr, short int count)
{
  unsigned short wCRCin = 0x0000;
  unsigned short wCPoly = 0x1021;
  unsigned char wChar = 0;
  while (count--)
  {
    wChar = *(ptr++);
    wCRCin ^= (wChar << 8);
    for (unsigned short i = 0; i < 8; i++)
    {
      if (wCRCin & 0x8000)
      {
        wCRCin = (wCRCin << 1) ^ wCPoly;
      }
      else
      {
        wCRCin = wCRCin << 1;
      }
    }
  }
  return (wCRCin);
}

void sendHeartbeat()
{
  uint8_t sBuf[256];
  unsigned short crc;
  uint16_t len = 0;

  sBuf[0] = TCOM_STX;       // 帧头
  sBuf[1] = TCOM_MSG_ACK;   // 消息类型
  sBuf[2] = 0x01;           // 协议版本
  sBuf[3] = TCOM_CMD_HEART; // 通信命令
  sBuf[4] = SequenceId;     // 消息流水号
  sBuf[5] = 0x00;           // 消息体长度
  sBuf[6] = 0x05;           // 消息体长度
  //
  sBuf[7] = HeartBeatVal++;
  sBuf[8] = 0x00;  // 预留：可做档位
  sBuf[9] = 0x00;  // 预留：其他
  sBuf[10] = 0x00; // 预留：可做电量显示
  sBuf[11] = 0x00; // 预留：可做菜单编号
  //
  len = ((sBuf[5] << 8) & 0xFF00) | sBuf[6];
  crc = luckin_calcrc(sBuf, len + 7);
  sBuf[len + 7] = (crc >> 8) & 0xFF;
  sBuf[len + 8] = crc & 0xFF;
  sendData(sBuf, len + 9);
}

// 运行完，上报结果
void sendRunResult()
{
  uint8_t sBuf[256];
  unsigned short crc;
  uint16_t len = 0;

  sBuf[0] = TCOM_STX;        // 帧头
  sBuf[1] = TCOM_MSG_ACK;    // 消息类型
  sBuf[2] = 0x01;            // 协议版本
  sBuf[3] = TCOM_CMD_RESULT; // 通信命令
  sBuf[4] = SequenceId;      // 消息流水号
  sBuf[5] = 0x00;            //
  // sBuf[6] = mtfreqptr/2*4+3;        //消息体长度
  sBuf[6] = 2; // 消息体长度，冰块重量：分别是高位、地位
  //
  sBuf[7] = 0; // 预留：可做档位
  // sBuf[8] = (uint8_t)MotorRunTime;  //预留：运行时长
  sBuf[8] = 0;
  // sBuf[9] = adc_volt_percent();  // 预留：电量e:\project\arduino\hankang\esp32s3_wifi_smartconfig\wifiSmartSocket\lib\WifiSmartconfig.h显示
  sBuf[9] = 0;
  uint8_t weight_str = 100;
  sBuf[10] = weight_str;
  // memcpy(sBuf + 10, weight_str, 3); // 冰块重量
  //
  len = ((sBuf[5] << 8) & 0xFF00) | sBuf[6];
  crc = luckin_calcrc(sBuf, len + 7);
  sBuf[len + 7] = (crc >> 8) & 0xFF;
  sBuf[len + 8] = crc & 0xFF;
  sendData(sBuf, len + 9);
}